﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace ConstantCMapEditor3
{
    public enum LayerState 
    {
        Layer1,
        Layer2,
        Layer3,
        Layer4,
        Layer5,
    }

    public class DelaySceneLayer  : Scene
    {
        //template method
        override public void RecursiveDraw(SpriteBatch batch, Vector2 parentPosition, float parentRotate, float scaleX, float scaleY, Color parentColor)
        {
            delayBatch = batch;
            delayParentPosition = parentPosition;
            delayParentRotate = parentRotate;
            delayScaleX = scaleX;
            delayScaleY = scaleY;
            delayParentColor = parentColor;

            Game1.delayDraw += mydelayDraw;
        }



        SpriteBatch delayBatch;
        Vector2 delayParentPosition;
        float delayParentRotate;
        float delayScaleX;
        float delayScaleY;
        Color delayParentColor;

        public void mydelayDraw() 
        {
            if (FixRotate)
            {
                delayParentRotate = 0;
            }

            _absoluteRotate = Rotate + delayParentRotate;
            _absoluteScaleX = _scaleX * delayScaleX;
            _absoluteScaleY = _scaleY * delayScaleY;


            double originRotate = Math.Atan(Position.Y / Position.X + 0.0001);

            if (Position.X == 0 && Position.Y == 0) originRotate = 0;
            else if (Position.X < 0) originRotate += Math.PI;

            _absolutePosition.X = delayScaleX * Position.Length() * (float)Math.Cos(delayParentRotate + originRotate) + delayParentPosition.X;
            _absolutePosition.Y = delayScaleY * Position.Length() * (float)Math.Sin(delayParentRotate + originRotate) + delayParentPosition.Y;

            AbsoluteDraw(delayBatch, _absolutePosition, _absoluteRotate, _absoluteScaleX, _absoluteScaleY, SpriteColor);

            foreach (Scene child in _childern)
            {
                child.RecursiveDraw(delayBatch, _absolutePosition, _absoluteRotate, _absoluteScaleX, _absoluteScaleY, _absoluteColor);
            }
        }
    }

    public class ThreeLayerSpriteScene : Scene
    {
        Scene layer1 = new Scene();
        Scene layer2 = new Scene();
        Scene layer3 = new Scene();
        Scene layer4 = new Scene();
        Scene layer5 = new DelaySceneLayer();

        bool view1 = true;
        bool view2 = true;
        bool view3 = true;
        bool view4 = true;
        bool view5 = true;

        PositionChecker Checker1 = new PositionChecker();
        PositionChecker Checker2 = new PositionChecker();
        PositionChecker Checker3 = new PositionChecker();
        PositionChecker Checker4 = new PositionChecker();
        PositionChecker Checker5 = new PositionChecker();

        private void setMouseEvent() 
        {
            layer1.TouchEvent = layer2.TouchEvent = layer3.TouchEvent = layer4.TouchEvent = layer5.TouchEvent = null;
            layer1.TouchEvent += GeneralEvent;
            layer2.TouchEvent += GeneralEvent;
            layer3.TouchEvent += GeneralEvent;
            layer4.TouchEvent += GeneralEvent;
            layer5.TouchEvent += GeneralEvent;
            ControlScene.TouchEvent += ControlSceneMouseEvent;
        }

        public bool ChangeView(int View)
        {
            BackToNormal();
            switch (View)
            {
                case 1:
                    view1 = !view1;
                    ResetView();
                    return view1;
                case 2:
                    view2 = !view2;
                    ResetView();
                    return view2;
                case 3:
                    view3 = !view3;
                    ResetView();
                    return view3;
                case 4:
                    view4 = !view4;
                    ResetView();
                    return view4;
                case 5:
                    view5 = !view5;
                    ResetView();
                    return view5;
                default:
                    throw new Exception("no this view");
            }
        }

        public void BackToNormal()
        {
            Action = EditorAction.Normal_Action;
            GetCurrentLayer().DettachChild(Rectangle);
            ControlScene.AlwaysTouchForPureScene = false;
            foreach (Declaration d in controlList)
            {
                d.UnFocus();
            }
            controlList.Clear();
            Game1.Selected = null;
        }

        static public EditorAction Action;
        public Sprite Rectangle = new Sprite(IntelligentTexture.IntelligentLoad("White"));
        Vector2 LeftTop;
        Vector2 RightDown;
        public Scene ControlScene = new Scene();
        public static List<Declaration> controlList = new List<Declaration>();
        public Vector2 MovingValue = new Vector2(0,0);

        public void DeleteClick()
        {
            if (!Game1.IsSelecting || !Game1.WorkSpaceLock)
            {
                if (controlList.Count > 0)
                {
                    List<Declaration> all = new List<Declaration>();
                    List<Command> allCommand = new List<Command>();

                    foreach (Declaration d in controlList)
                    {
                        allCommand.Add(((NormalSprite)d).GetDeleteCommand());
                        all.Add(d);
                    }

                    BatchDeleteSpriteCommand c = new BatchDeleteSpriteCommand(all, allCommand, controlList);
                    Game1.commandManager.Execute(c);
                }
            }
        }

        public void EdgeDown()
        {
                foreach (Declaration d in controlList)
                {
                    d.SelectedUpdate();
                }
        }

        public void ControlSceneMouseEvent(MouseEvent e, Scene s)
        {
            if (error)
            {
                if (e.ClickDownEdgeL && Keyboard.GetState().IsKeyDown(Keys.LeftControl) && Action != EditorAction.Select_Action)
                {
                    LeftTop = e.Position;
                    RightDown = e.Position;
                    Rectangle.Position = e.Position - Game1.CoordinateScene.Position;
                    Action = EditorAction.Select_Action;
                    return;
                }
                else if (Action == EditorAction.Select_Action)
                {
                    RightDown = e.Position;
                    Vector2 scale = RightDown - LeftTop;

                    if (scale.X < 0) scale.X = -scale.X;
                    if (scale.Y < 0) scale.Y = -scale.Y;

                    Vector2 MidPosition = (RightDown + LeftTop) / 2.0f;
                    Rectangle.ScaleX = scale.X;
                    Rectangle.ScaleY = scale.Y;
                    Rectangle.Position = MidPosition - Game1.CoordinateScene.Position;

                    List<Scene> touched = this.GetCurrentLayer().FindChildIsTouched(LeftTop - Game1.CoordinateScene.Position, RightDown - Game1.CoordinateScene.Position);

                    foreach (Declaration selectCandidate in controlList)
                    {
                        selectCandidate.UnFocus();
                    }

                    controlList.Clear();

                    foreach (Scene selectCandidate in touched)
                    {
                        if (!controlList.Contains(selectCandidate.UserData) && selectCandidate.UserData != null)
                        {
                            controlList.Add((Declaration)(selectCandidate.UserData));
                        }
                    }

                    foreach (Declaration selectCandidate in controlList)
                    {
                        selectCandidate.Focus();
                    }

                    if (e.ClickUpEdgeL || e.ClickUpEdgeM)
                    {
                        Action = EditorAction.Move_Action;
                        Rectangle.Scale = 0;
                    }
                }
                else if (Action == EditorAction.Move_Action)
                {
                    if (e.ClickDownEdgeM)
                    {
                        Action = EditorAction.Coordinate_Action;
                        return;
                    }


                    if (e.ClickDownEdgeL)
                    {
                        MovingValue = new Vector2(0, 0);
                        Dif = new Vector2(0, 0);
                        Scene touched = GetCurrentLayer().FindChildIsTouched(e.Position);

                        if (touched == null)
                        {
                            return;
                        }
                        else if (!controlList.Contains(touched.UserData))
                        {
                            BackToNormal();
                            touched.RecursiveTouch(e);
                            ControlScene.PressID = -1;

                            return;
                        }
                    }

                    if (e.ClickUpEdgeL&&controlList.Count > 0 && Dif != new Vector2(0, 0))
                    {
                        Command c = new BatchMoveSpriteCommand(controlList,Dif);
                        c.Undo();

                        Game1.commandManager.Execute(c);

                        Dif = new Vector2(0, 0);
                    }

                    if (e.PressedL)
                    {
                        if (!Game1.IsSelecting || !Game1.WorkSpaceLock)
                        {

                            MovingValue += e.Position - e.PrePosition;
                            
                            bool Lock = false;

                            foreach (Declaration d in controlList)
                            {
                                if (d is NormalSprite)
                                {
                                    Lock = ((NormalSprite)d).LockAt32 || Lock;
                                }
                            }

                            if (Lock)
                            {

                                while (MovingValue.X > 32)
                                {
                                    MovingValue -= new Vector2(32, 0);
                                    Dif += new Vector2(32, 0);
                                    foreach (Declaration d in controlList)
                                    {
                                        d.Position += new Vector2(32, 0);
                                    }
                                }

                                while (MovingValue.X < -32)
                                {
                                    MovingValue += new Vector2(32, 0);
                                    Dif -= new Vector2(32, 0);
                                    foreach (Declaration d in controlList)
                                    {
                                        d.Position -= new Vector2(32, 0);
                                    }
                                }

                                while (MovingValue.Y > 32)
                                {
                                    MovingValue -= new Vector2(0, 32);

                                    Dif += new Vector2(0, 32);
                                    foreach (Declaration d in controlList)
                                    {
                                        d.Position += new Vector2(0, 32);
                                    }
                                }

                                while (MovingValue.Y < -32)
                                {
                                    MovingValue += new Vector2(0, 32);
                                    Dif -= new Vector2(0, 32);
                                    foreach (Declaration d in controlList)
                                    {
                                        d.Position -= new Vector2(0, 32);
                                    }
                                }
                            }
                            else
                            {
                                Dif += MovingValue;
                                foreach (Declaration d in controlList)
                                {
                                    d.Position += MovingValue;
                                }
                                MovingValue = new Vector2(0, 0);
                            }
                        }
                    }
                }




                if (Action == EditorAction.Coordinate_Action)
                {
                    if (e.PressedM)
                    {
                        Game1.CoordinateScene.Position += e.Position - e.PrePosition;
                    }

                    if (e.ClickUpEdgeM)
                    {
                        Action = EditorAction.Move_Action;
                    }
                }

                if (e.ClickDownEdgeR)
                {
                    if (!Game1.IsSelecting || !Game1.WorkSpaceLock)
                    {

                        if (Keyboard.GetState().IsKeyDown(Keys.LeftControl))
                        {
                            if (controlList != null && controlList.Count > 0)
                            {

                                List<Declaration> tempList = new List<Declaration>();

                                foreach (Declaration selectCandidate in controlList)
                                {
                                    selectCandidate.UnFocus();
                                    tempList.Add(this.cloneSprite(selectCandidate));
                                }

                                Vector2 worldPosition = e.Position - Game1.CoordinateScene.Position - controlList[0].Position;
                                for (int i = 0; i < tempList.Count; i++)
                                {

                                    worldPosition -= new Vector2((int)worldPosition.X % 32, (int)worldPosition.Y % 32);

                                    Console.WriteLine(worldPosition);

                                    tempList[i].Position = controlList[i].Position + worldPosition;
                                }

                                controlList.Clear();


                                foreach (Declaration selectCandidate in tempList)
                                {
                                    selectCandidate.Focus();
                                    controlList.Add(selectCandidate);
                                }

                                List<Command> commandList = new List<Command>();

                                foreach (Declaration selectCandidate in controlList)
                                {
                                    commandList.Add(((NormalSprite)(selectCandidate)).GetDeleteCommand());
                                }

                                BatchCommand batch = new BatchCommand(commandList);
                                InvertCommand invert = new InvertCommand(batch);
                                invert.Undo();

                                Game1.commandManager.Execute(invert);
                                

                            }
                        }
                    }
                    else
                    {
                        BackToNormal();
                    }
                }

                if (Action == EditorAction.Select_Action && e.ClickUpEdgeL)
                {
                    Action = EditorAction.Move_Action;
                }
                error = false;
            }

        }

        public Vector2 Dif;

        static public bool error = true;

        public Declaration cloneSprite(Declaration target)
        {
            target.InstanceInit();

            Game1.declarationList[Game1.declarationList.Count - 1].RotateR = target.RotateR;
            Game1.declarationList[Game1.declarationList.Count - 1].Direction = target.Direction;
            Game1.declarationList[Game1.declarationList.Count - 1].Size = target.Size;
            if (target is NormalSprite)
            {
                ((NormalSprite)Game1.declarationList[Game1.declarationList.Count - 1]).sprite.SpriteColor = ((NormalSprite)target).sprite.SpriteColor;
                ((NormalSprite)Game1.declarationList[Game1.declarationList.Count - 1]).LockAt32 = ((NormalSprite)target).LockAt32;

                ((NormalSprite)Game1.declarationList[Game1.declarationList.Count - 1]).Mirror = ((NormalSprite)target).Mirror;
            }

            return Game1.declarationList[Game1.declarationList.Count - 1];
        }

        private void GeneralEvent(MouseEvent e, Scene s) 
        {

            if (e.ClickDownEdgeL && Keyboard.GetState().IsKeyDown(Keys.LeftControl) && Game1.Action == EditorAction.Normal_Action)
            {
                Action = EditorAction.Select_Action;
                GetCurrentLayer().AttachChild(Rectangle);

                LeftTop = e.Position;
                RightDown = e.Position;
                Rectangle.Position = e.Position - Game1.CoordinateScene.Position;

                ControlScene.AlwaysTouchForPureScene = true;
                ControlScene.PressID = e.ClickID;
                s.PressID = -1;
                Game1.Selected = null;
            }


            if (Action == EditorAction.Normal_Action)
            {
                if (Keyboard.GetState().IsKeyDown(Keys.LeftControl) && e.PressedR && Game1.Selected != null) 
                {
                    e.Position += new Vector2(16, 16);

                    Vector2 WidthHeight;



                    WidthHeight = new Vector2(Game1.Selected.sprite.Width, Game1.Selected.sprite.Height);


                    PositionInformation info = GetCurrentChecker().SpritePositionTranslation(e.Position - Game1.CoordinateScene.Position, WidthHeight, Game1.Selected.RotateR);

                    if (!GetCurrentChecker().IsCollide(info.PositionHolder) || e.ClickDownEdgeR)
                    {
                    Game1.Selected.InstanceInit();
                    Declaration temp = Game1.declarationList[Game1.declarationList.Count - 1];
                    temp.sprite.SpriteColor = Game1.Selected.sprite.SpriteColor;
                    temp.RotateR = Game1.Selected.RotateR;

                    if (temp is NormalSprite) ((NormalSprite)temp).LockAt32 = ((NormalSprite)Game1.Selected).LockAt32;
                    Game1.Selected = temp;
                    Game1.Selected.Position = e.Position - Game1.CoordinateScene.Position;

                    Command c;
                    c = ((NormalSprite)(Game1.Selected)).GetSelectDeleteCommand();
                    c = new InvertCommand(c);

                    c.Undo();
                    Game1.commandManager.Execute(c);
                    }
                }
                else if (e.PressedR&&!Keyboard.GetState().IsKeyDown(Keys.LeftControl))
                {
                    e.Position += new Vector2(16,16);
                    Vector2 WidthHeight = new Vector2(Game1.CandidateNormalSprite[Game1.SpriteEditorSelectedIndex].sprite.Width, Game1.CandidateNormalSprite[Game1.SpriteEditorSelectedIndex].sprite.Height);

                    PositionInformation info = GetCurrentChecker().SpritePositionTranslation(e.Position - Game1.CoordinateScene.Position, WidthHeight, 0);
                    if (!GetCurrentChecker().IsCollide(info.PositionHolder))
                    {
                        Game1.CandidateNormalSprite[Game1.SpriteEditorSelectedIndex].InstanceInit();
                        Game1.Selected = Game1.declarationList[Game1.declarationList.Count - 1];
                        Game1.Selected.Position = e.Position - Game1.CoordinateScene.Position;

                        if (Game1.Selected is NormalSprite)
                        {
                            Command c;
                            c = ((NormalSprite)(Game1.Selected)).GetSelectDeleteCommand();
                            c = new InvertCommand(c);

                            c.Undo();
                            Game1.commandManager.Execute(c);
                        }
                     }
                }

                if (e.PressedM)
                {
                    Game1.CoordinateScene.Position += e.Position - e.PrePosition;
                }

                if (KeyBoardManager.IsKeyEdgeDown(Keys.PageUp) && Game1.CoordinateScene.Scale > 0.5f) Game1.CoordinateScene.Scale -= 0.1f;
                if (KeyBoardManager.IsKeyEdgeDown(Keys.PageDown)) Game1.CoordinateScene.Scale += 0.1f;
                if (KeyBoardManager.IsKeyEdgeDown(Keys.Home)) Game1.CoordinateScene.Scale = 1.0f;
            }
        }
        

        public PositionChecker GetCurrentChecker() 
        {
            switch (LayerEditState)
            {
                case LayerState.Layer1:
                    return Checker1;
                case LayerState.Layer2:
                    return Checker2;
                case LayerState.Layer3:
                    return Checker3;
                case LayerState.Layer4:
                    return Checker4;
                case LayerState.Layer5:
                    return Checker5;
            }
            return Checker1;
        }

        public Scene GetCurrentLayer()
        {
            switch (LayerEditState)
            {
                case LayerState.Layer1:
                    return layer1;
                case LayerState.Layer2:
                    return layer2;
                case LayerState.Layer3:
                    return layer3;
                case LayerState.Layer4:
                    return layer4;
                case LayerState.Layer5:
                    return layer5;
            }
            return layer1;
        }

        public void Init() 
        {
            layer1.clearChild();
            layer2.clearChild();
            layer3.clearChild();
            layer4.clearChild();
            layer5.clearChild();

            layer1.AlwaysTouchForPureScene = true;
            layer2.AlwaysTouchForPureScene = true;
            layer3.AlwaysTouchForPureScene = true;
            layer4.AlwaysTouchForPureScene = true;
            layer5.AlwaysTouchForPureScene = true;

            Checker1.Init();
            Checker2.Init();
            Checker3.Init();
            Checker4.Init();
            Checker5.Init();

            ControlScene.Touchable = true;
            view1 = view2 = view3 = view4 = view5 = true;
            ResetView();
            LayerEditState = LayerState.Layer2;
            Rectangle.SpriteColor = new Color(20, 20, 20, 20);

            Action = EditorAction.Normal_Action;


            setMouseEvent();
        }

        public void attachToCurrentLayer(Scene scene) 
        {
            switch (LayerEditState)
            {
                case LayerState.Layer1:
                    layer1.AttachChild(scene);
                    break;
                case LayerState.Layer2:
                    layer2.AttachChild(scene);
                    break;
                case LayerState.Layer3:
                    layer3.AttachChild(scene);
                    break;
                case LayerState.Layer4:
                    layer4.AttachChild(scene);
                    break;
                case LayerState.Layer5:
                    layer5.AttachChild(scene);
                    break;
            }
        }

        public void dettachFromCurrentLayer(Scene scene) 
        {
            {
                    layer1.DettachChild(scene);
                    layer2.DettachChild(scene);
                    layer3.DettachChild(scene);
                    layer4.DettachChild(scene);
                    layer5.DettachChild(scene);
            }
        }

        public void ResetView()
        {
            this.clearChild();

            if (view1) this.AttachChild(layer1);
            if (view2) this.AttachChild(layer2);
            if (view3) this.AttachChild(layer3);
            if (view4) this.AttachChild(layer4);
            if (view5) this.AttachChild(layer5);

            this.AttachChild(ControlScene);
        }

        public LayerState LayerEditState
        {
            get 
            {
                return _layerEditState;
            }
            set 
            {
                switch (value) 
                {
                    case LayerState.Layer1:
                    layer1.Touchable = true;
                    layer2.Touchable = false;
                    layer3.Touchable = false;
                    layer4.Touchable = false;
                    layer5.Touchable = false;

                        break;
                    case LayerState.Layer2:
                    layer1.Touchable = false;
                    layer2.Touchable = true;
                    layer3.Touchable = false;
                    layer4.Touchable = false;
                    layer5.Touchable = false;
                        break;
                    case LayerState.Layer3:
                    layer1.Touchable = false;
                    layer2.Touchable = false;
                    layer3.Touchable = true;
                    layer4.Touchable = false;
                    layer5.Touchable = false;
                        break;
                    case LayerState.Layer4:
                        layer1.Touchable = false;
                        layer2.Touchable = false;
                        layer3.Touchable = false;
                        layer4.Touchable = true;
                        layer5.Touchable = false;
                        break;
                    case LayerState.Layer5:
                        layer1.Touchable = false;
                        layer2.Touchable = false;
                        layer3.Touchable = false;
                        layer4.Touchable = false;
                        layer5.Touchable = true;
                        break;
                }

                _layerEditState = value;
            }
        }

        private LayerState _layerEditState;
    }
}
